{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| default_exp js"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Javascript examples\n",
    "> Basic external Javascript lib wrappers"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To expedite fast development, FastHTML comes with several built-in Javascript and formatting components. These are largely provided to demonstrate FastHTML JS patterns. There's far too many JS libs for FastHTML to wrap them all, and as shown here the code to add FastHTML support is very simple anyway."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| exporti\n",
    "import re\n",
    "from fastcore.utils import *\n",
    "from fasthtml.components import *\n",
    "from fasthtml.xtend import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| export\n",
    "def light_media(\n",
    "        css: str # CSS to be included in the light media query\n",
    "    ):\n",
    "    \"Render light media for day mode views\"\n",
    "    return Style('@media (prefers-color-scheme: light) {%s}' %css)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "```html\n",
       "<style>@media (prefers-color-scheme: light) {.body {color: green;}}</style>\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "['style',\n",
       " ('@media (prefers-color-scheme: light) {.body {color: green;}}',),\n",
       " {}]"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "light_media('.body {color: green;}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| export\n",
    "def dark_media(\n",
    "        css: str # CSS to be included in the dark media query\n",
    "    ):\n",
    "    \"Render dark media for nught mode views\"\n",
    "    return Style('@media (prefers-color-scheme:  dark) {%s}' %css)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "```html\n",
       "<style>@media (prefers-color-scheme:  dark) {.body {color: white;}}</style>\n",
       "\n",
       "```"
      ],
      "text/plain": [
       "['style',\n",
       " ('@media (prefers-color-scheme:  dark) {.body {color: white;}}',),\n",
       " {}]"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dark_media('.body {color: white;}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| export\n",
    "marked_imp = \"\"\"import { marked } from \"https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js\";\n",
    "    import { proc_htmx } from \"https://cdn.jsdelivr.net/gh/answerdotai/fasthtml-js/fasthtml.js\";\n",
    "\"\"\"\n",
    "npmcdn = 'https://cdn.jsdelivr.net/npm/'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| export\n",
    "def MarkdownJS(\n",
    "        sel='.marked' # CSS selector for markdown elements\n",
    "    ):\n",
    "    \"Implements browser-based markdown rendering.\"\n",
    "    src = \"proc_htmx('%s', e => e.innerHTML = marked.parse(e.textContent));\" % sel\n",
    "    return Script(marked_imp+src, type='module')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Usage example [here](/tutorials/quickstart_for_web_devs.html#rendering-markdown)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "__file__ = '../../fasthtml/katex.js'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| export\n",
    "def KatexMarkdownJS(\n",
    "        sel='.marked',  # CSS selector for markdown elements\n",
    "        inline_delim='$',  # Delimiter for inline math\n",
    "        display_delim='$$',  # Delimiter for long math\n",
    "        math_envs=None  # List of environments to render as display math\n",
    "    ):\n",
    "    math_envs = math_envs or ['equation', 'align', 'gather', 'multline']\n",
    "    env_list = '[' + ','.join(f\"'{env}'\" for env in math_envs) + ']'\n",
    "    fn = Path(__file__).parent/'katex.js'\n",
    "    scr = ScriptX(fn, display_delim=re.escape(display_delim), inline_delim=re.escape(inline_delim),\n",
    "                  sel=sel, env_list=env_list, type='module')\n",
    "    css = Link(rel=\"stylesheet\", href=npmcdn+\"katex@0.16.11/dist/katex.min.css\")\n",
    "    return scr,css"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "KatexMarkdown usage example:\n",
    "\n",
    "```python\n",
    "longexample = r\"\"\"\n",
    "Long example:\n",
    "\n",
    "$$\\begin{array}{c}\n",
    "\n",
    "\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} &\n",
    "= \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\\n",
    "\n",
    "\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\\n",
    "\n",
    "\\nabla \\cdot \\vec{\\mathbf{B}} & = 0\n",
    "\n",
    "\\end{array}$$\n",
    "\"\"\"\n",
    "\n",
    "app, rt = fast_app(hdrs=[KatexMarkdownJS()])\n",
    "\n",
    "@rt('/')\n",
    "def get():\n",
    "    return Titled(\"Katex Examples\", \n",
    "        # Assigning 'marked' class to components renders content as markdown\n",
    "        P(cls='marked')(\"Inline example: $\\sqrt{3x-1}+(1+x)^2$\"),\n",
    "        Div(cls='marked')(longexample)\n",
    "    )\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| export\n",
    "def HighlightJS(\n",
    "        sel='pre code', # CSS selector for code elements. Default is industry standard, be careful before adjusting it\n",
    "        langs:str|list|tuple='python',  # Language(s) to highlight\n",
    "        light='atom-one-light',  # Light theme\n",
    "        dark='atom-one-dark'  # Dark theme\n",
    "    ):\n",
    "    \"Implements browser-based syntax highlighting. Usage example [here](/tutorials/quickstart_for_web_devs.html#code-highlighting).\"\n",
    "    src = \"\"\"\n",
    "hljs.addPlugin(new CopyButtonPlugin());\n",
    "hljs.configure({'cssSelector': '%s'});\n",
    "htmx.onLoad(hljs.highlightAll);\"\"\" % sel\n",
    "    hjs = 'highlightjs','cdn-release', 'build'\n",
    "    hjc = 'arronhunt'  ,'highlightjs-copy', 'dist'\n",
    "    if isinstance(langs, str): langs = [langs]\n",
    "    langjs = [jsd(*hjs, f'languages/{lang}.min.js') for lang in langs]\n",
    "    return [jsd(*hjs, f'styles/{dark}.css', typ='css', media=\"(prefers-color-scheme: dark)\"),\n",
    "            jsd(*hjs, f'styles/{light}.css', typ='css', media=\"(prefers-color-scheme: light)\"),\n",
    "            jsd(*hjs, f'highlight.min.js'),\n",
    "            jsd(*hjc, 'highlightjs-copy.min.js'),\n",
    "            jsd(*hjc, 'highlightjs-copy.min.css', typ='css'),\n",
    "            light_media('.hljs-copy-button {background-color: #2d2b57;}'),\n",
    "            *langjs, Script(src, type='module')]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| export\n",
    "def SortableJS(\n",
    "        sel='.sortable',  # CSS selector for sortable elements\n",
    "        ghost_class='blue-background-class'  # When an element is being dragged, this is the class used to distinguish it from the rest\n",
    "    ):\n",
    "    src = \"\"\"\n",
    "import {Sortable} from 'https://cdn.jsdelivr.net/npm/sortablejs/+esm';\n",
    "import {proc_htmx} from \"https://cdn.jsdelivr.net/gh/answerdotai/fasthtml-js/fasthtml.js\";\n",
    "proc_htmx('%s', Sortable.create);\n",
    "\"\"\" % sel\n",
    "    return Script(src, type='module')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "python3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
